package eecs.net.xmpp;
//Class: EECS 285
//Project: 4 (Virtual Markerboard)
//Due Date: Monday December 6th, 2010

//import org.jivesoftware.smack.Chat;
//import org.jivesoftware.smack.ChatManager;
//import org.jivesoftware.smack.ConnectionConfiguration;
//import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
//import org.jivesoftware.smack.MessageListener;
//import org.jivesoftware.smack.Roster;
//import org.jivesoftware.smack.XMPPConnection;
//import org.jivesoftware.smack.XMPPException;
//import org.jivesoftware.smack.filter.AndFilter;
//import org.jivesoftware.smack.filter.PacketFilter;
//import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
//import org.jivesoftware.smack.packet.PacketExtension;
//import org.jivesoftware.smack.packet.Presence;
//import org.jivesoftware.smack.packet.Presence.Type;

import eecs.net.xmpp.DataListener.CallType;

//import sun.reflect.Reflection;
import java.util.Map;
import java.util.TreeMap;

import java.util.regex.*;

import static eecs.util.Utility.*;

/**
 * A custom class that listens for incoming communication from this connection.
 * Internally, it discards any packets originating from clients who do not share
 * the same session ID. It also discards any packets that originated with this
 * client. The net effect is that clients only "see" data sent by Other Clients
 * in This Session. This class extracts POJO's (Plain Old Java Objects)
 * from the XML packets and passes them to a registered DataListener provided by
 * the client.
 * 
 * @author Vidal Borromeo
 */
public class EECSPacketListener implements PacketListener
{
  EECSXMPPConnection connection = null;
  DataListener dataListener = null;
  private DataListenerAsyncCall incomingCall = null;
  // ---------------------------------------------------------------------------

  /**
   * EECSPacketListener constructor. This is where the EECSXMPPConnection passes
   * in the DataListener that will be sent the POJO's (Plain Old Java Objects)
   * that were embedded in received XML packets.
   * 
   * @param listener_
   *          The instance of DataListener that the client provided to the
   *          EECSXMPPConnection constructor.
   * @author Vidal Borromeo
   */
  public EECSPacketListener(EECSXMPPConnection connection_,
      DataListener listener_)
  {
    connection = connection_;
    dataListener = listener_;
    incomingCall = new DataListenerAsyncCall(dataListener,CallType.INCOMING_SEMAPHORE,null);
  }

  // ---------------------------------------------------------------------------

  /**
   * Extracts the POJO's (Plain Old Java Objects) from the XML packet and sends
   * them along to the registered DataListener.
   * 
   * @param packet
   *          The incoming packet.
   * @author Vidal Borromeo
   */
  @Override
  public void processPacket(Packet packet)
  {
    debug("Receiving packet.");
      
    if( packet instanceof Message )
    {
      // Message msg = (Message) packet;
      // debug("Received Message: " + msg.getBody());
      // debug(packet.toXML());
    }
    else
    {
      debug("Received Non-Message Packet of type "
          + packet.getClass().getSimpleName() + ".");
      debug(packet.toXML());
      return;
    }

    debug("Processing packet: " + packet.getPacketID() + " FROM " + packet.getFrom());


    String fullID;
    String packetID;
    String sessionID;
    // Parse full ID into sessionID and PacketID.
    fullID = packet.getPacketID();
    if( fullID == null )
    {
      debug("Discarding packet. FullID is invalid.");
      return;
    }

    //debug("Parsing FullID \"" + fullID + "\"");
    String regExStr = "([^_]+)" + EECSXMPPConnection.ID_SEPARATOR + "([^_]+)";
    Pattern p = Pattern.compile(regExStr);
    Matcher m = p.matcher(fullID);
    if( !m.matches() )
    {
      debug("Discarding packet. FullID for incoming packet is invalid.");
      return;
    }

    sessionID = m.group(1);
    packetID = m.group(2);

    assert sessionID != null;
    assert packetID != null;

    //debug(String.format("sessionID: %s    packetID: %s", sessionID, packetID));

    // Ensure that:
    // 1) Packet is for the current session.
    // 2) Packet is Not from this client.
    // Return early if either is not true.
    if( !connection.isThisMySession(sessionID) )
    {
      debug("Discarding packet. Not from current session.");
      return;
    }
    else if( connection.didISendThisPacket(packetID) )
    {
      debug("Discarding packet. Packet originated here.");
      return;
    }
    
    // Notify lister of incoming packet.
    if( dataListener != null )
    {
      //dataListener.incomingSemaphore();
      (new Thread(incomingCall)).start();
    }

    debug("Packet is Valid. MESSAGE SIZE: " + packet.toXML().length());

    debug("Properties Are:");

    Map<String, Object> map = new TreeMap<String, Object>();
    // Grab the embedded property keys/values.
    for (String key : packet.getPropertyNames())
    {
      debug("Property: " + key);
      map.put(key, packet.getProperty(key));
    }

    // Pass them along to the registered listener.
    if( dataListener != null )
      dataListener.dataReceived(map);

  }// processPacket

}// EECSPacketListener
